/* Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdio.h>
#include <stdlib.h>

#include "iotsdk_sanitizers/ubsan.h"

/* Give the log a name when the callback is defined to PW_LOG_* (as it is in the example). */
#ifdef PW_LOG_MODULE_NAME
#undef PW_LOG_MODULE_NAME
#endif /* PW_LOG_MODULE_NAME */
#define PW_LOG_MODULE_NAME "ubsn"

#define GET_CALLER_ADDR() (uintptr_t) __builtin_extract_return_addr(__builtin_return_address(0))

#if defined(__ARMCOMPILER_VERSION)
#define HANDLER_RECOVER(name, msg)                                                         \
    void __ubsan_handle_##name##_minimal()                                                 \
    {                                                                                      \
        iotsdk_sanitizers_error_cb("UBSan error: " msg " [pc=0x%08x]", GET_CALLER_ADDR()); \
    }

#define HANDLER_NORECOVER(name, msg)                                                       \
    void __ubsan_handle_##name##_minimal_abort()                                           \
    {                                                                                      \
        iotsdk_sanitizers_error_cb("UBSan error: " msg " [pc=0x%08x]", GET_CALLER_ADDR()); \
        abort();                                                                           \
    }
#elif defined(__GNUC__)
#define HANDLER_RECOVER(name, msg)                                                         \
    void __ubsan_handle_##name()                                                           \
    {                                                                                      \
        iotsdk_sanitizers_error_cb("UBSan error: " msg " [pc=0x%08x]", GET_CALLER_ADDR()); \
    }

#define HANDLER_NORECOVER(name, msg)                                                       \
    void __ubsan_handle_##name##_abort()                                                   \
    {                                                                                      \
        iotsdk_sanitizers_error_cb("UBSan error: " msg " [pc=0x%08x]", GET_CALLER_ADDR()); \
        abort();                                                                           \
    }
#else
#error Unsupported compiler
#endif

#define HANDLER(name, msg)     \
    HANDLER_RECOVER(name, msg) \
    HANDLER_NORECOVER(name, msg)

HANDLER_RECOVER(builtin_unreachable, "Unreachable code reached (__builtin_unreachable)")
HANDLER_RECOVER(missing_return, "Reached end of non-void function without a return")
HANDLER(add_overflow, "Integer overflow (+)")
HANDLER(alignment_assumption, "alignment-assumption")
HANDLER(cfi_check_fail, "cfi-check-fail")
HANDLER(divrem_overflow, "Integer overflow (/ or %%)")
HANDLER(float_cast_overflow, "float-cast-overflow")
HANDLER(function_type_mismatch, "function-type-mismatch")
HANDLER(implicit_conversion, "Type conversion without a cast")
HANDLER(invalid_builtin, "invalid-builtin")
HANDLER(invalid_objc_cast, "invalid-objc-cast")
HANDLER(load_invalid_value, "load-invalid-value")
HANDLER(mul_overflow, "Integer overflow (*)")
HANDLER(negate_overflow, "Integer overflow (~)")
HANDLER(nonnull_arg, "Passed NULL to argument marked non-null")
HANDLER(nonnull_return, "nonnull-return")
HANDLER(out_of_bounds, "Out-of-bounds")
HANDLER(pointer_overflow, "Pointer overflow")
HANDLER(shift_out_of_bounds, "Shift out-of-bounds")
HANDLER(sub_overflow, "Integer overflow (-)")
HANDLER(vla_bound_not_positive, "vla-bound-not-positive")

#if defined(__ARMCOMPILER_VERSION)
HANDLER(type_mismatch, "Type mismatch")
HANDLER(nullability_arg, "nullability-arg")
HANDLER(nullability_return, "nullability-return")
#elif defined(__GNUC__)
HANDLER(type_mismatch_v1, "Type mismatch")
#endif
